#include "mythread.h"

// 构造函数，MyThread()函数是类MyThread的成员函数
MyThread::MyThread()
{
}


//获取系统cpu使用率(linux C)

typedef struct cpu_occupy_          //定义一个cpu occupy（cpu占用）的结构体
{
    char name[20];                  //定义一个char类型的数组名name有20个元素
    unsigned int user;              //定义一个无符号的int类型的user
    unsigned int nice;              //定义一个无符号的int类型的nice
    unsigned int system;            //定义一个无符号的int类型的system
    unsigned int idle;              //定义一个无符号的int类型的idle
    unsigned int iowait;
    unsigned int irq;
    unsigned int softirq;
}cpu_occupy_t;

double cal_cpuoccupy (cpu_occupy_t *o, cpu_occupy_t *n)
{
    double od, nd;
    double id, sd;
    double cpu_use ;

    od = (double) (o->user + o->nice + o->system +o->idle+o->softirq+o->iowait+o->irq);//第一次(用户+优先级+系统+空闲)的时间再赋给od
    nd = (double) (n->user + n->nice + n->system +n->idle+n->softirq+n->iowait+n->irq);//第二次(用户+优先级+系统+空闲)的时间再赋给od

    id = (double) (n->idle);    //用户第一次和第二次的时间之差再赋给id
    sd = (double) (o->idle) ;    //系统第一次和第二次的时间之差再赋给sd
    if((nd-od) != 0)
        cpu_use =100.0 - ((id-sd))/(nd-od)*100.00; //((用户+系统)乘100)除(第一次和第二次的时间差)再赋给g_cpu_used
    else
        cpu_use = 0;
    return cpu_use;
}

void get_cpuoccupy (cpu_occupy_t *cpust)
{
    FILE *fd;
    int n;
    char buff[256];
    cpu_occupy_t *cpu_occupy;
    cpu_occupy=cpust;

    fd = fopen ("/proc/stat", "r"); 
    if(fd == NULL)
    {
            perror("fopen:");
            exit (0);
    }
    fgets (buff, sizeof(buff), fd);

    sscanf (buff, "%s %u %u %u %u %u %u %u", cpu_occupy->name, &cpu_occupy->user, &cpu_occupy->nice,&cpu_occupy->system, &cpu_occupy->idle ,&cpu_occupy->iowait,&cpu_occupy->irq,&cpu_occupy->softirq); // cpu利用率参数格式化

    fclose(fd);
}

double get_sysCpuUsage()
{
    cpu_occupy_t cpu_stat1;
    cpu_occupy_t cpu_stat2;
    double cpu;
    get_cpuoccupy((cpu_occupy_t *)&cpu_stat1);
    sleep(1);
    //第二次获取cpu使用情况
    get_cpuoccupy((cpu_occupy_t *)&cpu_stat2);

    //计算cpu使用率
    cpu = cal_cpuoccupy ((cpu_occupy_t *)&cpu_stat1, (cpu_occupy_t *)&cpu_stat2);

    return cpu;
}

void MyThread::run()  //run()函数是类MyThread的成员函数
{
    int map_fd, prog_fd;
    struct bpf_link *link = NULL;
    struct bpf_program *prog;
    struct bpf_object *obj;

    obj = bpf_object__open_file("hello_kern.o", NULL);   //读取bpf的目标文件
    if (libbpf_get_error(obj)) {
        qDebug() << "ERROR: opening BPF object file failed\n";  //使用qDebug()函数把调试信息直接输出到控制台上；使用流的方法输出
        return;
    }

    prog = bpf_object__find_program_by_name(obj, "bpf_prog"); //在bpf的目标文件里面查找bpf程序。  *hello_kern.o ->“int bpf_prog(struct pt_regs *ctx)"
    if (!prog) {
        qDebug() <<"finding a prog in obj file failed\n";
    }


    if (bpf_object__load(obj)) {  //加载bpf程序
        qDebug() <<"ERROR: loading BPF object file failed\n";
    }

    map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");      //获取my_map对应的句柄     * my_map是一段内存空间，在bpf程序里面创建， 作用是 bpf获取的数据通过这段内存共享给用户态程序
    if (map_fd < 0 ) {
        qDebug() <<"ERROR: finding a map in obj file failed\n";
    }

    link = bpf_program__attach(prog);  //将bpf程序俯加到内核函数

    if (libbpf_get_error(link)) {
        qDebug() <<"ERROR: bpf_program__attach failed\n";
        link = NULL;
    }

    struct procInfo proc;	//procinfo使用proc_info_list结构体，用来说明一个cpu的信息，包括这个cpu的ID号，对应的内核数据映射区的MMU标识等等
    int result;

    int index = 123;  //在map里面的键值   *map的存储方式是 一个键值对应一段内容

    QStringList items;	//QStringList类提供了一个字符串列表
    QString statusText;
    FILE* fp;
    char buf[100] = {0};
    char command[300] = {0};
    char *q;
    char *q2;
    while (!isInterruptionRequested())
    {
        qDebug() << "Running...";

        result = bpf_map_lookup_elem(map_fd, &index, &proc);  //让proc数据结构指针 指向 位于map的键值为123(index = 123)的内存
        if(result == 0){
            if( proc.uid == 0){
                printf("%s\t\t\t", "root");
                items<<"root";     //当uid = 0时，表示是root用户
            }else if(proc.uid == 1000){
                items<<"shihaolin";   //等于1000时表示是 账号为shihaolin的用户
            }
            if( proc.gid == 0){
                items<<"root";			//当gid = 0时，表示是root用户组
            }else if(proc.gid == 1000){
                items<<"shihaolin"; //等于1000时表示是 账号为shihaolin的用户组
            }
            statusText = statusText.sprintf("CPU利用率: %.2f", get_sysCpuUsage());

            sprintf(command, "ps aux | grep ' %u ' | awk 'NR==1' | awk '{print $3,$4}' | tr \"\n\" \" \"", proc.pid); //拼接命令获取进程的内存利用率和cpu利用率

            if((fp = popen(command, "r")) != NULL){  //通过管道获取
                fgets(buf, sizeof(buf), fp);   //读取返回的内存利用率和cpu利用率
                qDebug() << command;
                pclose(fp);
            }


            items<<QString("%1").arg(proc.tgid)<<QString("%1").arg(proc.pid)<<buf<<proc.name<<statusText;	//输出tgid、pid、buf、name、CPU利用率
            memset(command, 0, sizeof(command));  //字符串数组清0
            memset(buf, 0, sizeof(buf));//字符串数组清0
            sleep(1);
            emit updateUI(items);  //发送信号，信号槽收到信号执行绑定的函数；mythread线程发射信号通知mainwindow线程界面更新请求；mainwindow线程根据具体信号以及信号参数对界面组件进行修改
            qDebug() << items;
            items.clear();
        }
    }
    qDebug() << "Get Interruption Request, I'll exit.";
}
